/*****************************************************************************/
/*                                                                           */
/*    Domino Operation System Driver Module                                  */
/*    SED1335 LCD Controller driver                                          */
/*                                                                           */
/*    Copyright (C) 2005 Laszlo Arvai                                        */
/*                                                                           */
/*****************************************************************************/

///////////////////////////////////////////////////////////////////////////////
// Includes
#include <avr/io.h>
#include <krnlSystemTimer.h>
#include "drvIOConfig.h"
#include "guiLCDDriver.h"
#include "sysSettings.h"
#include "drvSED1335.h"
#include "guiFrameBuffer.h"

///////////////////////////////////////////////////////////////////////////////
// Macros
///////////////////////////////////////////////////////////////////////////////
// Write byte to the command port
#define LCDWriteCommand( x ) { _SFR_MEM8(SED1335_LCD_COMMAND) = (x);	SED1335_DELAY();}
#define LCDWriteData(x) { _SFR_MEM8(SED1335_LCD_DATA) = (x); SED1335_DELAY();}

///////////////////////////////////////////////////////////////////////////////
// Module local variables
static dosWord l_text_cursor_address;

///////////////////////////////////////////////////////////////////////////////
// Global variables

///////////////////////////////////////////////////////////////////////////////
// Init LCD driver
void guiInitLCDDriver(void)
{
  dosWord i;

	// init
	l_text_cursor_address = drvMA_TEXT_SCREEN;

	// init mode port pins
	initSED1335RESET();
	initLCD_BACKLIGHT();
	guiEnableBacklight(dosFalse);

	SED1335RESET(PIN_LOW);
	krnlDelay(2);
	SED1335RESET(PIN_HIGH);
	krnlDelay(4);
	
	// System set
  LCDWriteCommand(0x40);
  LCDWriteData(0x30);
  LCDWriteData(0x87);
  LCDWriteData(0x07);
  LCDWriteData(0x27);
  LCDWriteData(0x3c);
  LCDWriteData(0xef);
  LCDWriteData(0x28);
  LCDWriteData(0x00);

	// scroll
  LCDWriteCommand(0x44);
  LCDWriteData(0x00);
  LCDWriteData(0x00);
  LCDWriteData(0xef);
  LCDWriteData(0xb0);
  LCDWriteData(0x04);
  LCDWriteData(0xef);
  LCDWriteData(0x00);
  LCDWriteData(0x00);
  LCDWriteData(0x00);
  LCDWriteData(0x00);
  LCDWriteData(0x00);

	// cursor form
  LCDWriteCommand(0x5d);
  LCDWriteData(0x04);
  LCDWriteData(0x86);

	// cursor direction
  LCDWriteCommand(0x4c);

	// horizpntal scroll rate
  LCDWriteCommand(0x5a);
  LCDWriteData(0x00);

	// overlay
  LCDWriteCommand(0x5b);
  LCDWriteData(0x01);

	// display on
  LCDWriteCommand(0x59);
  LCDWriteData(0x16);

	// clear graphics display  
  LCDWriteCommand(0x46);
  LCDWriteData(LOW(drvMA_GRAPHICS_SCREEN));
  LCDWriteData(HIGH(drvMA_GRAPHICS_SCREEN));

  LCDWriteCommand(0x42);
  for(i=0; i<9600; i++)
		LCDWriteData(0x00);

	// clear char display
	guiTextClearScreen();

	// turn backlight on
	guiEnableBacklight(dosTrue);
}

///////////////////////////////////////////////////////////////////////////////
// Clear character screen
void guiTextClearScreen(void)
{
	dosWord i;

	// clear character screen
  LCDWriteCommand(0x46);
  LCDWriteData(LOW(drvMA_TEXT_SCREEN));
  LCDWriteData(HIGH(drvMA_TEXT_SCREEN));

	LCDWriteCommand(0x42);
	for(i=0;i<1200;i++)	
		LCDWriteData(0x20);

	l_text_cursor_address = 0;
}

///////////////////////////////////////////////////////////////////////////////
// Set text screen cursor pos
void guiTextSetCursorPos( dosByte in_x, dosByte in_y )
{
	// check coordinates
	if( in_x >= guiTEXT_SCREEN_WIDTH )
		in_x = guiTEXT_SCREEN_WIDTH - 1;

	if( in_y >= guiTEXT_SCREEN_HEIGTH )
		in_y = guiTEXT_SCREEN_HEIGTH - 1;
		
	// calculate cursor address
	l_text_cursor_address = drvMA_TEXT_SCREEN + in_y * guiTEXT_SCREEN_WIDTH + in_x;
}

///////////////////////////////////////////////////////////////////////////////
// Write character onto the text screen
void guiTextWriteChar(dosChar in_char )
{
  LCDWriteCommand(0x46);
  LCDWriteData( LOW( l_text_cursor_address ) );
  LCDWriteData( HIGH( l_text_cursor_address ) );

	LCDWriteCommand(0x42);
	LCDWriteData(in_char);

	// move cursor to the next character and wrap around the screen
	l_text_cursor_address++;
	if( l_text_cursor_address >= drvMA_TEXT_SCREEN + guiTEXT_SCREEN_WIDTH * guiTEXT_SCREEN_HEIGTH )
		l_text_cursor_address = drvMA_TEXT_SCREEN;
}

///////////////////////////////////////////////////////////////////////////////
// Update canvas
void guiUpdateCanvas( dosInt16 in_left, dosInt16 in_top, dosInt16 in_right, dosInt16 in_bottom )
{
	dosWord row_address;
	dosWord row_length;
	dosWord y;
	dosWord address;

	// calculate address
	row_address = in_top * guiFRAME_BUFFER_ROW_LENGTH + in_left / guiBITS_PER_PIXEL;
	row_length = in_right / guiBITS_PER_PIXEL - in_left / guiBITS_PER_PIXEL + 1;

	// cursor direction
	LCDWriteCommand(0x4c);

	// rows (lines)
	for( y = in_top; y <= in_bottom; y++ )
	{
		// set cursor position
	  LCDWriteCommand(0x46);
	  LCDWriteData( LOW( row_address + drvMA_GRAPHICS_SCREEN ) );
	  LCDWriteData( HIGH( row_address + drvMA_GRAPHICS_SCREEN ) );
	
		// write memory command
		LCDWriteCommand(0x42);

		// wait for retrace
		while( ( _SFR_MEM8(SED1335_LCD_STATUS) & 0x40 ) != 0 );
		while( ( _SFR_MEM8(SED1335_LCD_STATUS) & 0x40 ) == 0 );

		// copy row
		for( address = row_address; address < row_address + row_length; address++ )
		{
			_SFR_MEM8(SED1335_LCD_DATA) = g_frame_buffer[address];
			SED1335_DELAY();
		}

		row_address += guiFRAME_BUFFER_ROW_LENGTH;
	}
}

///////////////////////////////////////////////////////////////////////////////
// Turn backlight on and off
void guiEnableBacklight(dosBool in_enabled)
{
	if( in_enabled )
		LCD_BACKLIGHT(PIN_HIGH);
	else
		LCD_BACKLIGHT(PIN_LOW);
}
